#include "StdAfx.h"
#include "SRObjModelLoader.h"
#include "SRObjModel.h"

using namespace sora;
using std::string;
using std::vector;
using std::auto_ptr;
using matsu::vec4;
using matsu::vec3;
using matsu::vec2;
using matsu::equalAbsError;

#if _IPHONE_
#pragma mark ObjNodeVertexNormalState
#endif
TEST(ObjNodeVertexNormalState, parse)
{
	string line;
	vector<string> tokens;
	auto_ptr<ObjNodeState> state(new ObjNodeVertexNormalState(NULL));
	ObjNodeData data;

	//vertex normal
	line = "vn 0.577350 0.577350 -0.577350";
	tokens = ObjModelParser::parser().split(line);
	state->parse(tokens, data);
	EXPECT_EQ(ObjNodeKeywordVertexNormal, data.keyword());
	EXPECT_EQ(3, data.valueCnt);
	EXPECT_TRUE(equalAbsError<double>(0.577350, data.value[0], 0.1));
	EXPECT_TRUE(equalAbsError<double>(0.577350, data.value[1], 0.1));
	EXPECT_TRUE(equalAbsError<double>(-0.577350, data.value[2], 0.1));
}

TEST(ObjNodeVertexNormalState, update)
{
	MeshModelBuilder builer;
	auto_ptr<ObjNodeFSM> fsm(new ObjNodeFSM());
	ObjNodeState &state = fsm->state(ObjNodeKeywordVertexNormal);

	//create node data
	ObjNodeData data;
	string line = "vn 0.577350 0.577350 -0.577350";
	vector<string> tokens = ObjModelParser::parser().split(line);
	state.parse(tokens, data);

	state.update(data, builer);

	//check result
	const vec3 &normal = fsm->normal(1);
	EXPECT_TRUE(equalAbsError<double>(normal.x, 0.577350, 0.1));
	EXPECT_TRUE(equalAbsError<double>(normal.y, 0.577350, 0.1));
	EXPECT_TRUE(equalAbsError<double>(normal.z, -0.577350, 0.1));
}
#if _IPHONE_
#pragma mark ObjNodeGeometricVertexState
#endif
TEST(ObjNodeGeometricVertexState, parse)
{
	string line;
	vector<string> tokens;
	ObjNodeData data;
	auto_ptr<ObjNodeState> state(new ObjNodeGeometricVertexState(NULL));

	//geometric vertex
	line = "v 0.577350 0.577350 -0.577350";
	tokens = ObjModelParser::parser().split(line);
	state->parse(tokens, data);
	EXPECT_EQ(ObjNodeKeywordGeometricVertex, data.keyword());
	EXPECT_EQ(3, data.valueCnt);
	EXPECT_TRUE(abs(0.577350 - data.value[0]) < 0.1);
	EXPECT_TRUE(abs(0.577350 - data.value[1]) < 0.1);
	EXPECT_TRUE(abs(-0.577350 - data.value[2]) < 0.1);
	EXPECT_TRUE(abs(1.0 - data.value[3]) < 0.1);

	line = "v 0.577350 0.577350 -0.577350 1";
	tokens = ObjModelParser::parser().split(line);
	state->parse(tokens, data);
	EXPECT_EQ(ObjNodeKeywordGeometricVertex, data.keyword());
	EXPECT_EQ(4, data.valueCnt);
	EXPECT_TRUE(abs(0.577350 - data.value[0]) < 0.1);
	EXPECT_TRUE(abs(0.577350 - data.value[1]) < 0.1);
	EXPECT_TRUE(abs(-0.577350 - data.value[2]) < 0.1);
	EXPECT_TRUE(abs(1 - data.value[3]) < 0.1);
}

TEST(ObjNodeGeometricVertexState, update)
{
	MeshModelBuilder builder;
	auto_ptr<ObjNodeFSM> fsm(new ObjNodeFSM());
	ObjNodeState &state = fsm->state(ObjNodeKeywordGeometricVertex);

	string line;
	vector<string> tokens;
	ObjNodeData data;

	line = "v 1 2 3";
	tokens = ObjModelParser::parser().split(line);
	state.parse(tokens, data);
	state.update(data, builder);

	line = "v 2 3 4 5";
	tokens = ObjModelParser::parser().split(line);
	state.parse(tokens, data);
	state.update(data, builder);

	//check result
	const vec4 &p1 = fsm->pos(1);
	EXPECT_EQ(p1.x, 1);
	EXPECT_EQ(p1.y, 2);
	EXPECT_EQ(p1.z, 3);
	EXPECT_EQ(p1.w, 1);

	const vec4 &p2 = fsm->pos(2);
	EXPECT_EQ(p2.x, 2);
	EXPECT_EQ(p2.y, 3);
	EXPECT_EQ(p2.z, 4);
	EXPECT_EQ(p2.w, 5);
}
#if _IPHONE_
#pragma mark ObjNodeParameterSpaceVertexState
#endif
TEST(ObjNodeParameterSpaceVertexState, parse)
{
	string line;
	vector<string> tokens;
	ObjNodeData data;
	auto_ptr<ObjNodeState> state(new ObjNodeParameterSpaceVertexState(NULL));

	line = "vp 0.577350 0.577350 -0.577350";
	tokens = ObjModelParser::parser().split(line);
	state->parse(tokens, data);
	EXPECT_EQ(ObjNodeKeywordParameterSpaceVertex, data.keyword());
	EXPECT_EQ(3, data.valueCnt);
	EXPECT_TRUE(abs(0.577350 - data.value[0]) < 0.1);
	EXPECT_TRUE(abs(0.577350 - data.value[1]) < 0.1);
	EXPECT_TRUE(abs(-0.577350 - data.value[2]) < 0.1);

	line = "vp 0.577350 0.577350";
	tokens = ObjModelParser::parser().split(line);
	state->parse(tokens, data);
	EXPECT_EQ(ObjNodeKeywordParameterSpaceVertex, data.keyword());
	EXPECT_EQ(2, data.valueCnt);
	EXPECT_TRUE(abs(0.577350 - data.value[0]) < 0.1);
	EXPECT_TRUE(abs(0.577350 - data.value[1]) < 0.1);
	EXPECT_TRUE(abs(1.0 - data.value[2]) < 0.1);

	line = "vp 0.577350";
	tokens = ObjModelParser::parser().split(line);
	state->parse(tokens, data);
	EXPECT_EQ(ObjNodeKeywordParameterSpaceVertex, data.keyword());
	EXPECT_EQ(1, data.valueCnt);
	EXPECT_TRUE(abs(0.577350 - data.value[0]) < 0.1);
	EXPECT_TRUE(abs(1.0 - data.value[1]) < 0.1);
	EXPECT_TRUE(abs(1.0 - data.value[2]) < 0.1);
}
#if _IPHONE_
#pragma mark ObjNodeTextureVertexState
#endif
TEST(ObjNodeTextureVertexState, parse)
{
	string line;
	vector<string> tokens;
	ObjNodeData data;

	//texture vertex
	auto_ptr<ObjNodeState> state(new ObjNodeTextureVertexState(NULL));

	line = "vt 0.577350 0.577350 -0.577350";
	tokens = ObjModelParser::parser().split(line);
	state->parse(tokens, data);
	EXPECT_EQ(ObjNodeKeywordTextureVertex, data.keyword());
	EXPECT_EQ(3, data.valueCnt);
	EXPECT_TRUE(abs(0.577350 - data.value[0]) < 0.1);
	EXPECT_TRUE(equalAbsError<double>(0.577350, data.value[1], 0.1));
	EXPECT_TRUE(equalAbsError<double>(-0.577350, data.value[2], 0.1));

	line = "vt 0.577350 0.577350";
	tokens = ObjModelParser::parser().split(line);
	state->parse(tokens, data);
	EXPECT_EQ(ObjNodeKeywordTextureVertex, data.keyword());
	EXPECT_EQ(2, data.valueCnt);
	EXPECT_TRUE(abs(0.577350 - data.value[0]) < 0.1);
	EXPECT_TRUE(abs(0.577350 - data.value[1]) < 0.1);
	EXPECT_TRUE(abs(0 - data.value[2]) < 0.1);

	line = "vt 0.577350";
	tokens = ObjModelParser::parser().split(line);
	state->parse(tokens, data);
	EXPECT_EQ(ObjNodeKeywordTextureVertex, data.keyword());
	EXPECT_EQ(1, data.valueCnt);
	EXPECT_TRUE(abs(0.577350 - data.value[0]) < 0.1);
	EXPECT_TRUE(abs(0 - data.value[1]) < 0.1);
	EXPECT_TRUE(abs(0 - data.value[2]) < 0.1);
}

TEST(ObjNodeTextureVertexState, update)
{
	MeshModelBuilder builer;
	auto_ptr<ObjNodeFSM> fsm(new ObjNodeFSM());
	ObjNodeState &state = fsm->state(ObjNodeKeywordTextureVertex);

	string line;
	vector<string> tokens;
	ObjNodeData data;

	line = "vt 0.1 0.2 0.3";
	tokens = ObjModelParser::parser().split(line);
	state.parse(tokens, data);
	state.update(data, builer);

	line = "vt 0.1 0.2";
	tokens = ObjModelParser::parser().split(line);
	state.parse(tokens, data);
	state.update(data, builer);

	line = "vt 0.1";
	tokens = ObjModelParser::parser().split(line);
	state.parse(tokens, data);
	state.update(data, builer);

	//check result
	const vec2 &tex1 = fsm->texCoord(1);
	EXPECT_TRUE(equalAbsError<double>(0.1, tex1.x, 0.001));
	EXPECT_TRUE(equalAbsError<double>(0.2, tex1.y, 0.001));

	const vec2 &tex2 = fsm->texCoord(2);
	EXPECT_TRUE(equalAbsError<double>(0.1, tex2.x, 0.001));
	EXPECT_TRUE(equalAbsError<double>(0.2, tex2.y, 0.001));

	const vec2 &tex3 = fsm->texCoord(3);
	EXPECT_TRUE(equalAbsError<double>(0.1, tex3.x, 0.001));
	EXPECT_TRUE(equalAbsError<double>(0, tex3.y, 0.001));
}
#if _IPHONE_
#pragma mark ObjNodeFaceState
#endif
TEST(ObjNodeFaceState, parse)
{
	string line;
	vector<string> tokens;
	ObjNodeData data;
	//face
	auto_ptr<ObjNodeState> state(new ObjNodeFaceState(NULL));

	//vertex
	line = "f 1 2 3 4";
	state->parse(line, data);
	EXPECT_EQ(ObjNodeKeywordFace, data.keyword());
	EXPECT_EQ(false, data.useNormal);
	EXPECT_EQ(false, data.useTex);
	EXPECT_EQ(4, data.intCnt());

	//vertex-tex
	line = "f 1/1 2/2 3/3 4/4";
	state->parse(line, data);
	EXPECT_EQ(ObjNodeKeywordFace, data.keyword());
	EXPECT_EQ(false, data.useNormal);
	EXPECT_EQ(true, data.useTex);
	EXPECT_EQ(8, data.intCnt());

	//vertex-normal
	line = "f 1//1 2//2 3//3 4//4";
	state->parse(line, data);
	EXPECT_EQ(ObjNodeKeywordFace, data.keyword());
	EXPECT_EQ(true, data.useNormal);
	EXPECT_EQ(false, data.useTex);
	EXPECT_EQ(8, data.intCnt());

	//vertex-tex-normal
	line = "f 1/1/1 2/2/2 3/3/3 4/4/4";
	state->parse(line, data);
	EXPECT_EQ(ObjNodeKeywordFace, data.keyword());
	EXPECT_EQ(true, data.useNormal);
	EXPECT_EQ(true, data.useTex);
	EXPECT_EQ(12, data.intCnt());
}
#if _IPHONE_
#pragma mark ObjNodeMaterialLibraryState
#endif

TEST(ObjNodeMaterialLibraryState, parse)
{
	string line;
	vector<string> tokens;
	ObjNodeData data;
	auto_ptr<ObjNodeState> state(new ObjNodeMaterialLibraryState(NULL));

	line = "mtllib cube.mtl";
	state->parse(line, data);
	EXPECT_EQ(ObjNodeKeywordMaterialLibrary, data.keyword());
	EXPECT_STREQ("cube.mtl", data.str(0).c_str());
}
#if _IPHONE_
#pragma mark ObjNodeMaterialNameState
#endif
TEST(ObjNodeMaterialNameState, parse)
{
	string line;
	vector<string> tokens;
	ObjNodeData data;
	auto_ptr<ObjNodeState> state(new ObjNodeMaterialNameState(NULL));

	line = "usemtl red";
	state->parse(line, data);
	EXPECT_EQ(ObjNodeKeywordMaterialName, data.keyword());
	EXPECT_STREQ("red", data.str(0).c_str());
}
#if _IPHONE_
#pragma mark ObjNodeGroupNameState
#endif
TEST(ObjNodeGroupNameState, parse)
{
	string line;
	vector<string> tokens;
	ObjNodeData data;
	auto_ptr<ObjNodeState> state(new ObjNodeGroupNameState(NULL));

	line = "g default";
	state->parse(line, data);
	EXPECT_EQ(ObjNodeKeywordGroupName, data.keyword());
	EXPECT_STREQ("default", data.str(0).c_str());
}
